package org.jaaksi.kottlindemo.coroutines

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.annotation.MainThread
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.activity_test_cou.*
import kotlinx.coroutines.*
import libcore.kotpref.KotPref.context
import org.jaaksi.kottlindemo.R
import kotlin.coroutines.CoroutineContext

class TestSuspendActivity : AppCompatActivity() {

    private val handler = Handler(Looper.getMainLooper())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test_cou)

        btn_click.setOnClickListener {
            testMainImmediate()
        }

    }

    /**
     * HandlerDispatcher中进行处理
     * Dispatchers.Main和Dispatchers.Main.immediate的区别
     * fixme Dispatchers.Main和Dispatchers.Main.immediate的区别：
     * 都运行在主线程。
     * 如果原本就在主线程：
     * 前者不会立刻执行，而需要被调度
     * 后者不切换线程的时候（如都在主线程），不进行调度，立刻执行
     *
     */
    // 伪代码
//    private fun dispatchEvent(block: Runnable){
//        if (dispatcher.isDispatchNeeded(context)) {
//            dispatcher.dispatch(context, block)
//        } else {
//            // 直接执行
//            block.run()
//            // 或者加到队列中
//            queue.add(block)
//        }
//    }

//    override fun isDispatchNeeded(context: CoroutineContext): Boolean {
    // 如果是非immediate或者当前线程或者调度器制定的线程不一致则需要调度
//        return !invokeImmediately || Looper.myLooper() != handler.looper
//    }

    // 调度就是handler.post
//    override fun dispatch(context: CoroutineContext, block: Runnable) {
//        handler.post(block)
//    }

    /**
     * 执行结果：3 4 7 1 5 2 6
     * MainScope方法实现：ContextScope(SupervisorJob() + Dispatchers.Main)
     *
     * 分析：
     * 举个例子：排队做核酸1带着孩子2，有两个队列，一个是紧急的（3，4，7...），一个低优先级队列。低优先级队列要等高优队列的人做完才做。
     * MainScope().launch{1，2}虽然在前面，但是1不着急，被调度到低优先队列
     * 3排到最前面，后面是4，再后面是1
     * 3做完后，机器坏了，1s后才能修好，大家都得等着
     * 1s后机器修好了。4开始。
     * 5由于是post的，也是在低优先级队列，也就是在1和2的后面。
     * 4结束后，又来一个着急的人7，进到了高优队列。7开始做。
     * 7做完1开始。
     * 1做完后该2了，小孩2说想尿尿，于是离队了（挂起。1替他排着等他回来），所以轮到5开始做
     * 6也是post的，也是在低优先级队列的队尾
     * 由于6post了200毫秒，1的小孩2 100毫秒后，回来了，所以5结束后是1做（两个时间不能相差太短。协程挂起恢复也需要好似）
     * 1结束后是6
     *
     * 因为是MainScope（Dispatchers.Main）会被调度，被安排在主线程队列尾部,所以1不会先执行；
     * 主线程执行3，阻塞1s，执行4，
     *
     */
    private fun testMainScope() {
        val job = MainScope().launch {
            println(">>1 delay")
            delay(100)
            println(">>2 coroutine end")
        }
        println(">>3 Thread sleep start")
        Thread.sleep(1000)
        println(">>4 Thread sleep end")
//        job.cancel()
        handler.post {
            println(">>5 post")
        }
        handler.postDelayed({
            println(">>6 postDelayed 80")
        },200)
//        Thread.sleep(3000)
        println(">>7")

    }

    /**
     * 运行结果：1 3 4 2 5
     * 由于方法本身是运行在主线程的，协程闭包也运行在主线程，所以immediate这里不进行调度，直接执行，所以先执行1
     * 1执行完，挂起1000毫秒，（因为是挂起，不是阻塞）主线程继续向下执行，所以3执行
     * 3结束后，线程阻塞1秒，执行4
     * 4执行完毕后，由于5是post的，放到队列尾部。协程挂起1s(在线程阻塞的1s后也结束了），协程恢复，所以执行2，最后执行5
     *
     * 变动：
     * 1.如果协程delay 1010毫秒，那执行结果是 1 3 4 5 2。
     * 因为协程还没有恢复，还处于挂起状态，所以会先执行5
     *
     * 2.如果协程delay 100毫秒，执行结果不变
     * 因为此时主线程被阻塞了，协程是无法恢复的。阻塞结束后，由于队列仍在执行，所以要等。
     * 可以通过断点，看协程的声明周期，何时执行，何时挂起，何时恢复
     */
    private fun testMainImmediate() { // 协程的调度(挂起、恢复、切换线程）是由Handler完成的？？
        val scope = CoroutineScope(Dispatchers.Main.immediate)
        val job = scope.launch {
            println(">>1 delay")
            // 协程被挂起，主线程继续执行下面的代码
            delay(100) // 挂起1s相当于postDelay 1s
            println(">>2 coroutine end")
        }
        println(">>3 Thread sleep start")
        Thread.sleep(1000)
        println(">>4 Thread sleep end")
//        job.cancel()
        handler.post {
            println(">>5 post")
        }

    }
}